<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>

                    <h4>文档测试</h4>
                    <div class="x-wiki-info"><span>403次阅读</span></div>
                    <hr style="border-top-color:#ccc" />
                    <div class="x-wiki-content x-content"><p>如果你经常阅读Python的官方文档，可以看到很多文档都有示例代码。比如<a href="https://docs.python.org/2/library/re.html">re模块</a>就带了很多示例代码：</p>
<pre><code>&gt;&gt;&gt; import re
&gt;&gt;&gt; m = re.search(&#39;(?&lt;=abc)def&#39;, &#39;abcdef&#39;)
&gt;&gt;&gt; m.group(0)
&#39;def&#39;
</code></pre><p>可以把这些示例代码在Python的交互式环境下输入并执行，结果与文档中的示例代码显示的一致。</p>
<p>这些代码与其他说明可以写在注释中，然后，由一些工具来自动生成文档。既然这些代码本身就可以粘贴出来直接运行，那么，可不可以自动执行写在注释中的这些代码呢？</p>
<p>答案是肯定的。</p>
<p>当我们编写注释时，如果写上这样的注释：</p>
<pre><code>def abs(n):
    &#39;&#39;&#39;
    Function to get absolute value of number.

    Example:

    &gt;&gt;&gt; abs(1)
    1
    &gt;&gt;&gt; abs(-1)
    1
    &gt;&gt;&gt; abs(0)
    0
    &#39;&#39;&#39;
    return n if n &gt;= 0 else (-n)
</code></pre><p>无疑更明确地告诉函数的调用者该函数的期望输入和输出。</p>
<p>并且，Python内置的“文档测试”（doctest）模块可以直接提取注释中的代码并执行测试。</p>
<p>doctest严格按照Python交互式命令行的输入和输出来判断测试结果是否正确。只有测试异常的时候，可以用<code>...</code>表示中间一大段烦人的输出。</p>
<p>让我们用doctest来测试上次编写的<code>Dict</code>类：</p>
<pre><code>class Dict(dict):
    &#39;&#39;&#39;
    Simple dict but also support access as x.y style.

    &gt;&gt;&gt; d1 = Dict()
    &gt;&gt;&gt; d1[&#39;x&#39;] = 100
    &gt;&gt;&gt; d1.x
    100
    &gt;&gt;&gt; d1.y = 200
    &gt;&gt;&gt; d1[&#39;y&#39;]
    200
    &gt;&gt;&gt; d2 = Dict(a=1, b=2, c=&#39;3&#39;)
    &gt;&gt;&gt; d2.c
    &#39;3&#39;
    &gt;&gt;&gt; d2[&#39;empty&#39;]
    Traceback (most recent call last):
        ...
    KeyError: &#39;empty&#39;
    &gt;&gt;&gt; d2.empty
    Traceback (most recent call last):
        ...
    AttributeError: &#39;Dict&#39; object has no attribute &#39;empty&#39;
    &#39;&#39;&#39;
    def __init__(self, **kw):
        super(Dict, self).__init__(**kw)

    def __getattr__(self, key):
        try:
            return self[key]
        except KeyError:
            raise AttributeError(r&quot;&#39;Dict&#39; object has no attribute &#39;%s&#39;&quot; % key)

    def __setattr__(self, key, value):
        self[key] = value

if __name__==&#39;__main__&#39;:
    import doctest
    doctest.testmod()
</code></pre><p>运行<code>python mydict.py</code>：</p>
<pre><code>$ python mydict.py
</code></pre><p>什么输出也没有。这说明我们编写的doctest运行都是正确的。如果程序有问题，比如把<code>__getattr__()</code>方法注释掉，再运行就会报错：</p>
<pre><code>$ python mydict.py
**********************************************************************
File &quot;mydict.py&quot;, line 7, in __main__.Dict
Failed example:
    d1.x
Exception raised:
    Traceback (most recent call last):
      ...
    AttributeError: &#39;Dict&#39; object has no attribute &#39;x&#39;
**********************************************************************
File &quot;mydict.py&quot;, line 13, in __main__.Dict
Failed example:
    d2.c
Exception raised:
    Traceback (most recent call last):
      ... 
    AttributeError: &#39;Dict&#39; object has no attribute &#39;c&#39;
**********************************************************************
</code></pre><p>注意到最后两行代码。当模块正常导入时，doctest不会被执行。只有在命令行运行时，才执行doctest。所以，不必担心doctest会在非测试环境下执行。</p>
<h3 id="-">小结</h3>
<p>doctest非常有用，不但可以用来测试，还可以直接作为示例代码。通过某些文档生成工具，就可以自动把包含doctest的注释提取出来。用户看文档的时候，同时也看到了doctest。</p>
</div>

                    <hr style="border-top-color:#ccc" />

                    